from fill_in_error import __, assert_equal

# python use for to iterate a data structure

class AboutIteration:
    def use_range_to_get_a_C_like_loop():
        # you can choose end number for range
        sum = 0
        for i in range(3):
            sum += i
        assert_equal(sum, __)

        # you can also choose start number
        sum = 0
        for i in range(1, 6):
            sum += i
        assert_equal(sum, __)

        # you can also choose step size
        sum = 0
        for i in range(1, 6, 2):
            sum += i
        assert_equal(sum, __)

        # reversed order?
        a_number = 0
        for i in range(100, 1, -1):
            if i % 33 == 0:
                a_number = i
                break
        assert_equal(a_number, __)

    def iterate_a_list():
        a_list = [3, 1, 2]

        # let's write a min function 
        # to find the minimum element of a list
        min_a_of_list = 100
        for elem in a_list:
            if min_a_of_list > elem:
                min_a_of_list = elem
        assert_equal(min_a_of_list, __)

        # another min function!
        # however, this time we just want to know
        # the index of the minimum element
        a_list = [1, 3, 2]
        index_of_min = 0
        for i in range(len(a_list)):
            if a_list[index_of_min] > a_list[i]:
                index_of_min = i
        assert_equal(index_of_min, __)

        # this time we want both index and element!
        # actually, I don't like use explicit index when iterating!
        # and range(len(a_list)) is ugly!
        # so try to use the enumerate()
        a_list = [1, 3, 2]
        index_of_min, min_a_of_list = 0, 100
        # i is index and elem is the element itself
        # pretty cool, right?
        for i, elem in enumerate(a_list):
            if min_a_of_list > elem:
                index_of_min = i
                min_a_of_list = elem
        assert_equal(index_of_min, __)
        assert_equal(min_a_of_list, __)

        # WARNING!
        # it is not allowed to change the size of the list
        # in the iteration!
        # uncomment the following code to see what happens

        # unlucky_list = [1]
        # for elem in unlucky_list:
        #     unlucky_list.append(1)
    
    def iterate_a_dict():
        fruit_price = {'banana':2, 'apple': 3, 'pear': 1}
        
        # sorry:(, I didn't come up with a good example...
        # so let's write a stupid function
        # which seek banana and get its price
        price_of_banana = 0
        for k, v in fruit_price.items():
            if k == 'banana':
                price_of_banana = v
                break
        assert_equal(price_of_banana, __)

        # you can only iterate the keys
        for k in fruit_price.keys():
            # lalala
            pass
        
        # or only the values
        for v in fruit_price.values():
            # lalala
            pass
    
    def iterate_two_list_at_the_same_time():
        list_a = [1, 2 ,3]
        list_b = [4, 5, 6]
        
        # we want a list_c to store the sum each pair of list_a and b
        # like this, list_c = [1+4, 2+5, 3+6]
        # we use zip to achieve this
        list_c = []
        for i, j in zip(list_a, list_b):
            list_c.append(i + j)
        assert_equal(list_c, __)

        # magic comes!
        list_c = [i * j for i, j in zip(list_a, list_b)]
        assert_equal(list_c, __)